#include "socket.hpp"
#include <poll.h>
#include <memory>

const static int defaultfd = -1;
const static short defaultevents = 0;
const static int default_timeout = 1000;

class PollServer
{
    const static int nfds = 1024;

public:
    PollServer(uint16_t port)
        : _port(port), _listensock(std::make_unique<net::TcpSocket>())
    {
        InetAddr addr = {"0", port};
        _listensock->BuildServerSocket(addr);
        for (int i = 0; i < nfds; i++)
        {
            fds[i].fd = defaultfd;
            fds[i].events = defaultevents;
            fds[i].revents = defaultevents;
        }
        fds[0].fd = _listensock->SockFd();
        fds[0].events = POLLIN;
    }

    ~PollServer()
    {
        _listensock->Close();
    }

    void Loop()
    {
        while (true)
        {
            int timeout = default_timeout;
            int n = poll(fds, nfds, timeout);
            if (n > 0)
            {
                execute();
            }
            else if (n < 0)
            {
                Log(ERROR, "%s", strerror(errno));
            }
            else
            {
                // Log(DEBUG, "time out %d", timeout);
            }
        }
    }

    void execute()
    {
        for (int i = 0; i < nfds; i++)
        {
            if (fds[i].fd == defaultfd)
            {
                continue;
            }
            if (fds[i].revents & POLLIN)
            {
                if (fds[i].fd == _listensock->SockFd()) // 收到新的连接
                {
                    InetAddr clientaddr;
                    net::socket_ptr ptr = _listensock->Accept(&clientaddr);
                    Log(INFO, "Have a connection fd:%d %s:%d", ptr->SockFd(), clientaddr.ip().c_str(), clientaddr.port());
                    int pos = 1;
                    while (pos < nfds)
                    {
                        if (fds[pos].fd == defaultfd)
                        {
                            fds[pos].fd = ptr->SockFd();
                            fds[pos].events = POLLIN;
                            Log(INFO, "add pollfd array success");
                            break;
                        }
                        pos++;
                    }
                    if (pos == nfds)
                    {
                        // 扩容或者关闭
                        ptr->Close();
                    }
                }
                else
                {
                    char buffer[1024];
                    int fd = fds[i].fd;
                    short revent = fds[i].revents;
                    int n = recv(fd, buffer, sizeof(buffer) - 1, 0);
                    if (n > 0)
                    {
                        buffer[n] = '\0';
                        std::cout << "client echo# " << buffer << std::endl;
                        std::string str("server echo# ");
                        str += buffer;
                        send(fd, str.c_str(), str.size(), 0);
                    }
                    else if (n == 0) // 客户端要退出了
                    {
                        Log(INFO, "A client is about to exit.fd:%d", fd);
                        fds[i].fd = defaultfd;
                        fds[i].events = defaultevents;
                        fds[i].revents = defaultevents;
                        close(fd);
                    }
                    else // 出错了
                    {
                        Log(INFO, "%s", strerror(errno));
                        fds[i].fd = defaultfd;
                        fds[i].events = defaultevents;
                        fds[i].revents = defaultevents;
                        close(fd);
                        continue;
                    }
                }
            }
        }
    }

private:
    uint16_t _port;
    struct pollfd fds[nfds];
    std::unique_ptr<net::Socket> _listensock;
};
const int PollServer::nfds;
